/*
 *  Copyright (c) 2011 Leibniz Institute of Plant Genetics and Crop Plant Research (IPK), Gatersleben, Germany.
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the GNU Lesser Public License v2.1
 *  which accompanies this distribution, and is available at
 *  http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 *
 *  Contributors:
 *      Leibniz Institute of Plant Genetics and Crop Plant Research (IPK), Gatersleben, Germany - RMI Client, FileChooser and WebDAV
 */
package de.ipk_gatersleben.bit.bi.edal.webdav.wrapper.primary_data;

import java.io.IOException;
import java.io.InputStream;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.bind.JAXBException;

import io.milton.resource.CollectionResource;
import io.milton.resource.PropFindableResource;
import io.milton.resource.PutableResource;
import io.milton.resource.Resource;
import io.milton.http.Auth;
import io.milton.http.Request;
import io.milton.http.Request.Method;
import io.milton.http.exceptions.BadRequestException;
import io.milton.http.exceptions.ConflictException;
import io.milton.http.exceptions.NotAuthorizedException;

import de.ipk_gatersleben.bit.bi.edal.primary_data.file.PrimaryDataDirectoryException;
import de.ipk_gatersleben.bit.bi.edal.primary_data.file.PrimaryDataEntityVersionException;
import de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.MetaData;
import de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.MetaDataException;
import de.ipk_gatersleben.bit.bi.edal.primary_data.security.EdalAuthenticateException;
import de.ipk_gatersleben.bit.bi.edal.rmi.client.ClientDataManager;
import de.ipk_gatersleben.bit.bi.edal.rmi.client.ClientPrimaryDataDirectory;
import de.ipk_gatersleben.bit.bi.edal.rmi.client.ClientPrimaryDataEntity;
import de.ipk_gatersleben.bit.bi.edal.rmi.client.ClientPrimaryDataEntityVersion;
import de.ipk_gatersleben.bit.bi.edal.webdav.wrapper.FileSystemHandler;
import de.ipk_gatersleben.bit.bi.edal.webdav.wrapper.metadata.ExtXMLConfig;
import de.ipk_gatersleben.bit.bi.edal.webdav.wrapper.metadata.Property;

/**
 * A class enabling to browse version information for the specified folder.
 * 
 * @author jinbo
 * 
 */

public class PrimaryDataVersionDirectoryVirtualResource extends
		PrimaryDataEntityResource implements CollectionResource,
		PutableResource {
	private ClientPrimaryDataDirectory dir;

	public PrimaryDataVersionDirectoryVirtualResource(String path,
			FileSystemHandler fileSystemHandler) throws RemoteException,
			PrimaryDataDirectoryException, NotBoundException,
			EdalAuthenticateException {
		super(path, fileSystemHandler);
		if (entity != null) {
			dir = (ClientPrimaryDataDirectory) entity;
		}
	}

	public ClientPrimaryDataDirectory getDir() {
		return this.dir;
	}

	@Override
	public boolean authorise(Request request, Method method, Auth auth) {
		boolean b = super.authorise(request, method, auth);
		if (entity != null) {
			dir = (ClientPrimaryDataDirectory) entity;
		}
		return b;
	}

	@Override
	public String getName() {
		return FileSystemHandler.VIRTUALVERSIONFOLDERPREFIX;
		/*
		 * try { return FileSystemHandler.FILEPREFIX+entity.getName(); } catch
		 * (RemoteException e) {
		 * ClientDataManager.logger.error("Failed to get name of: " + dir +
		 * "\nReason: " + e.toString()); } return null;
		 */
	}

	@Override
	public Resource child(String childName) {
		try {
			if (this.dir.exist(childName)) {
				PrimaryDataEntityResource child = new PrimaryDataEntityResource(
						this.dir.getPrimaryDataEntity(childName).getPath(),
						fileSystemHandler);
				if (child.isDirectory()) {
					return (PrimaryDataDirectoryResource) child;
				} else {
					// files inside a directory are either
					Pattern property = Pattern
							.compile(".*\\.v[0-9]+\\.?[^\\.]*\\.properties\\.xml$");
					Matcher pm = property.matcher(childName);

					// virtual files
					if (!pm.matches()) {
						return new PrimaryDataFileDirectoryVirtualResource(
								entity.getPath(), fileSystemHandler);
						// or property files
					} else {
						return new PrimaryDataEntityPropertyVirtualResource(
								entity.getCurrentVersion(), entity
										.getCurrentVersion().getRevision());
					}
				}
			}
		} catch (RemoteException e) {
			ClientDataManager.logger.error("Failed to get resource for: "
					+ childName + "\nReason: " + e.toString());
		} catch (PrimaryDataDirectoryException e) {
			ClientDataManager.logger.error("Failed to get resource for: "
					+ childName + "\nReason: " + e.toString());
		} catch (JAXBException e) {
			ClientDataManager.logger.error("Failed to get resource for: "
					+ childName + "\nReason: " + e.toString());
		} catch (MetaDataException e) {
			ClientDataManager.logger.error("Failed to get resource for: "
					+ childName + "\nReason: " + e.toString());
		} catch (NotBoundException e) {
			ClientDataManager.logger.error("Failed to get resource for: "
					+ childName + "\nReason: " + e.toString());
		} catch (EdalAuthenticateException e) {
			ClientDataManager.logger.error("Failed to get resource for: "
					+ childName + "\nReason: " + e.toString());
		}

		return null;
	}

	@Override
	public List<? extends Resource> getChildren() {
		List<PropFindableResource> children = new ArrayList<PropFindableResource>();
		try {
			List<ClientPrimaryDataEntity> lis = dir.listPrimaryDataEntities();
			for (ClientPrimaryDataEntity ent : lis) {
				if (!ent.isDirectory()) {
					children.add(new PrimaryDataFileDirectoryVirtualResource(
							ent.getPath(), fileSystemHandler));
				} else {
					children.add(new PrimaryDataDirectoryVirtualResource(ent
							.getPath(), fileSystemHandler));
				}
			}
			// current folder versions metadata information
			if (!dir.getPath().equals("/")) {
				SortedSet<ClientPrimaryDataEntityVersion> versions = dir
						.getVersions();
				for (ClientPrimaryDataEntityVersion v : versions) {
					if (v.getRevision() > -1L) {
						children.add(new PrimaryDataEntityPropertyVirtualResource(
								v, v.getRevision()));
					}
				}
			}
		} catch (RemoteException e) {
			ClientDataManager.logger.error("Failed to get children of: " + dir
					+ "\n" + e.toString());
		} catch (PrimaryDataDirectoryException e) {
			ClientDataManager.logger.error("Failed to get children of: " + dir
					+ "\n" + e.toString());
		} catch (NotBoundException e) {
			ClientDataManager.logger.error("Failed to get children of: " + dir
					+ "\n" + e.toString());
		} catch (EdalAuthenticateException e) {
			ClientDataManager.logger.error("Failed to get children of: " + dir
					+ "\n" + e.toString());
		} catch (JAXBException e) {
			ClientDataManager.logger
					.error("Failed to create properties.xml of: " + dir + "\n"
							+ e.toString());
		} catch (MetaDataException e) {
			ClientDataManager.logger
					.error("Failed to create properties.xml of: " + dir
							+ "\n: " + e.toString());
		}

		return children;
	}

	@Override
	public Resource createNew(String newName, InputStream inputStream,
			Long length, String contentType) throws IOException,
			ConflictException, NotAuthorizedException, BadRequestException {
		if (newName.contains("properties.xml")) {
			// TODO save changes in properties.xml
			ExtXMLConfig conf;
			try {
				conf = new ExtXMLConfig(Property.class);
				Object rawData = conf.load(inputStream);
				if (rawData != null) {
					Property metaData = (Property) rawData;
					Pattern property = Pattern
							.compile("(.*)\\.v[0-9]+\\.?[^\\.]*\\.(properties?\\.?xml|.*)$");
					Matcher pm = property.matcher(newName);
					if (pm.matches()) {
						ClientPrimaryDataEntity dirfile = fileSystemHandler
								.getEntity(dir.getPath());
						if (dirfile != null) {
							MetaData newMetaData = dirfile.getMetaData()
									.clone();
							metaData.updateMetaData(newMetaData);
							dirfile.setMetaData(newMetaData);
							fileSystemHandler.removecache(dir.getPath());

							PrimaryDataEntityPropertyVirtualResource virtualxmlresouce = new PrimaryDataEntityPropertyVirtualResource(
									dirfile.getCurrentVersion(), dirfile
											.getCurrentVersion().getRevision());
							return virtualxmlresouce;
						}
					}

				}
			} catch (JAXBException e) {
				ClientDataManager.logger
						.error("Failed to save properties-file: " + newName
								+ "\nReason: " + e.toString());
			} catch (RemoteException e) {
				ClientDataManager.logger
						.error("Failed to save properties-file: " + newName
								+ "\nReason: " + e.toString());
			} catch (CloneNotSupportedException e) {
				ClientDataManager.logger
						.error("Failed to save properties-file: " + newName
								+ "\nReason: " + e.toString());
			} catch (PrimaryDataEntityVersionException e) {
				ClientDataManager.logger
						.error("Failed to save properties-file: " + newName
								+ "\nReason: " + e.toString());
			} catch (MetaDataException e) {
				ClientDataManager.logger
						.error("Failed to save properties-file: " + newName
								+ "\nReason: " + e.toString());
			} catch (PrimaryDataDirectoryException e) {
				ClientDataManager.logger
						.error("Failed to save properties-file: " + newName
								+ "\nReason: " + e.toString());
			}
		} else {
			throw new NotAuthorizedException("don't support this operation!",
					this);
		}
		return null;
	}

}
